package com.niiwoo.civet.account.service.local.openAccount2.listener;

import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.enums.OpenAccountRecordStatusEnum;
import com.niiwoo.civet.account.enums.OpenAccountWayEnum;
import com.niiwoo.civet.account.service.local.openAccount2.dto.OpenAccountEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class OpenAccountListeners implements ApplicationContextAware {

    private ApplicationContext ctx;

    private List<OpenAccountListener> listenerList = new ArrayList<>(0);

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (applicationContext.getParent() == null) ctx = applicationContext;
    }

    @PostConstruct
    public void init() {
        Optional.ofNullable(ctx.getBeansOfType(OpenAccountListener.class)).ifPresent(m -> listenerList.addAll(m.values()));
    }

    /**
     * 异步处理监听事件
     */
    public void onNotify(OpenAccountEvent event) {
        String traceId = UUID.randomUUID().toString();
        log.info("开户监听事件###{}###请求, traceId={}, data={}", this.getClass().getSimpleName(), traceId, JSON.toJSONString(event));
        OpenAccountRecordStatusEnum status = OpenAccountRecordStatusEnum.of(event.getRecord().getStatus());
        OpenAccountWayEnum way = OpenAccountWayEnum.of(event.getRecord().getOpenAccountWay());
        listenerList.stream()
                .filter(l -> l.isExpectStatus(status) && l.isInterestedOpenAccountWay(way))
                .forEach(l -> {
                    log.info("开户监听事件###{}###请求, traceId={}", l.getClass().getSimpleName(), traceId);
                    CompletableFuture.runAsync(() -> l.handle(event)).whenComplete((aVoid, throwable) -> {
                        if (throwable != null) {
                            log.error(String.format("开户监听事件####%s##异常, traceId=%s, errorMessage=%s", l.getClass().getSimpleName(), traceId, throwable.getMessage()), throwable);
                        } else {
                            log.info("开户监听事件###{}###成功, traceId={}", l.getClass().getSimpleName(), traceId);
                        }
                    });
                });

    }

}
